package com.cta.service.impl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cta.constant.ProfileType;
import com.cta.constant.ProfileUserMapping;
import com.cta.dao.ProfilePersistence;
import com.cta.entity.Contact;
import com.cta.entity.PBX;
import com.cta.entity.PBXFactory;
import com.cta.entity.Profile;
import com.cta.entity.ServiceProvider;
import com.cta.entity.Trunk;
import com.cta.exception.CTAServiceException;
import com.cta.service.ProfileService;

@Service("profileService")
@Transactional(readOnly = true)
public class ProfileServiceImpl implements ProfileService {

	@Autowired
	private ProfilePersistence profilePersistence;

	/**
	 * create provider
	 * 
	 * @param name
	 * @param description
	 */
	@Transactional(readOnly = false)
	public ServiceProvider createServiceProvider(String name, String description) {
		ServiceProvider pr = new ServiceProvider(name, description, Calendar.getInstance().getTime());
		return profilePersistence.save(pr);
	}

	/**
	 * update service provider
	 * 
	 * @param serviceProviderId
	 * @param name
	 * @param description
	 * @return
	 */
	@Transactional(readOnly = false)
	public ServiceProvider updateServiceProvider(Long serviceProviderId, String name, String description) {
		ServiceProvider pr = profilePersistence.findById(ServiceProvider.class, serviceProviderId);
		pr.setName(name);
		pr.setDescription(description);
		return pr;
	}

	/**
	 * check name of service provider
	 * 
	 * @param name
	 * @return
	 */
	public boolean hasServiceProviderName(String name) {
		ServiceProvider serviceProvider = profilePersistence.findSingleObject(ServiceProvider.class, "name", name);
		return serviceProvider != null ? true : false;
	}

	/**
	 * find service provider by id
	 * 
	 * @param pbxServiceProviderId
	 * @return
	 */
	public ServiceProvider findServiceProviderById(Long serviceProviderId) {
		return profilePersistence.findById(ServiceProvider.class, serviceProviderId);
	}

	/**
	 * find all Provider
	 * 
	 * @return
	 */
	public List<ServiceProvider> findAllProviders() {
		return profilePersistence.findAllProviders();
	}

	/**
	 * create trunk
	 * 
	 * @param name
	 * @param description
	 * @return
	 */
	@Transactional(readOnly = false)
	public Trunk createTrunk(String trunkNo, String name, String description, Long serviceProviderId, Long pbxId,
			Long configId) {
		ServiceProvider serviceProvider = profilePersistence.findById(ServiceProvider.class, serviceProviderId);
		PBX pbx = profilePersistence.findById(PBX.class, pbxId);
		Trunk tr = new Trunk(trunkNo, name, description, Calendar.getInstance().getTime(), serviceProvider, pbx,
				configId);
		return profilePersistence.save(tr);
	}

	/**
	 * update trunk
	 * 
	 * @param trunkId
	 * @param name
	 * @param description
	 * @param serviceProviderId
	 * @param pbxId
	 * @return
	 */
	@Transactional(readOnly = false)
	public void updateTrunk(Long trunkId, String trunkNo, String name, String description, Long serviceProviderId,
			Long pbxId, Long configId) {
		Trunk trunk = profilePersistence.findById(Trunk.class, trunkId);
		PBX pbx = profilePersistence.findById(PBX.class, pbxId);
		trunk.setTrunkNo(trunkNo);
		trunk.setName(name);
		trunk.setDescription(description);
		trunk.setPbx(pbx);
		trunk.setConfigId(configId);
	}

	/**
	 * find all Trunk
	 * 
	 * @return
	 */
	public List<Trunk> findAllTrunks() {
		return profilePersistence.findAllTrunks();
	}

	/**
	 * find list of trunk base on service provider id
	 * 
	 * @param serviceProviderId
	 * @return
	 */
	public List<Trunk> findTrunkByProvider(Long serviceProviderId) {
		return profilePersistence.findTrunkByProvider(serviceProviderId);
	}

	/**
	 * find trunk base on id
	 * 
	 * @param serviceProviderId
	 * @return
	 */
	public Trunk findTrunkById(Long id) {
		Trunk trunk = profilePersistence.findById(Trunk.class, id);
		if (trunk.getServiceProvider() != null) {
			trunk.getServiceProvider().getId();
		}
		if (trunk.getPbx() != null) {
			trunk.getPbx().getId();
		}
		return trunk;
	}

	/**
	 * create pbx factory
	 * 
	 * @param name
	 * @param description
	 * @return
	 */
	@Transactional(readOnly = false)
	public PBXFactory createPBXFactory(String name, String description) {
		PBXFactory pbx = new PBXFactory(name, description, Calendar.getInstance().getTime());
		return profilePersistence.save(pbx);
	}

	/**
	 * update pbx factory
	 * 
	 * @param factoryId
	 * @param name
	 * @param description
	 * @return
	 */
	@Transactional(readOnly = false)
	public PBXFactory editPBXFactory(Long factoryId, String name, String description) {
		PBXFactory pbx = profilePersistence.findById(PBXFactory.class, factoryId);
		if (pbx != null) {
			pbx.setName(name);
			pbx.setDescription(description);
		}
		return pbx;
	}

	/**
	 * check if this name has exist on db
	 * 
	 * @param name
	 * @return
	 */
	public boolean hasPBXFactoryName(String name) {
		PBXFactory pbxFactory = profilePersistence.findSingleObject(PBXFactory.class, "name", name);
		return pbxFactory != null ? true : false;
	}

	/**
	 * find all pbx factory
	 * 
	 * @return
	 */
	public List<PBXFactory> findAllPBXFactories() {
		return profilePersistence.findAllPBXFactories();
	}

	/**
	 * find pbx factory by id
	 * 
	 * @return
	 */
	public PBXFactory findPBXFactory(Long pbxFactoryId) {
		return profilePersistence.findById(PBXFactory.class, pbxFactoryId);
	}

	/**
	 * find all profile of pbx and eager load pbx
	 * 
	 * @return
	 */
	public List<Profile> findProfileByPBXId(Long pbxId) {
		List<Profile> profiles = profilePersistence.findProfileByPBXId(pbxId);
		return profiles;
	}

	/**
	 * find all profile of pbx and eager load pbx
	 * 
	 * @return
	 */
	public List<Profile> findProfileByPBXNo(String pbxNo) {
		List<Profile> profiles = profilePersistence.findProfileByPBXNo(pbxNo);
		return profiles;
	}

	/**
	 * save profile of pbx
	 * 
	 * @param id
	 * @param name
	 * @param description
	 * @param pbxId
	 * @return
	 */
	@Transactional(readOnly = false)
	public void saveProfile(List<Object> profileData, String timeFormat, String dateFormat, String durationFormat,
			Long pbxId) throws CTAServiceException {
		PBX pbx = profilePersistence.findById(PBX.class, pbxId);
		if (pbx == null) {
			throw new CTAServiceException("PBX not found");
		}
		List<Profile> profiles = findProfileByPBXId(pbx.getId());
		List<Profile> remains = new ArrayList<Profile>();
		int sequence = 0;
		for (Object obj : profileData) {
			Map<String, Object> map = (Map<String, Object>) obj;
			String column = (String) map.get("column");
			String name = (String) map.get("name");
			Integer numOfbytes = (Integer) map.get("numOfbytes");
			Integer space = (Integer) map.get("space");
			String columnMapping = (String) map.get("columnMapping");
			sequence++;
			Profile profile = profilePersistence.getProfileByColumnAndPbx(column, pbxId);
			if (profile == null) {
				Profile p = new Profile(sequence, column, name, name, numOfbytes, space, ProfileType.MAPPING, pbx,
						ProfileUserMapping.valOf(columnMapping));
				p = profilePersistence.save(p);
				remains.add(p);
			} else {
				profile.setNumOfBytes(numOfbytes);
				profile.setSpace(space);
				profile.setSequence(sequence);
				profile.setColumnMapping(ProfileUserMapping.valOf(columnMapping));
				remains.add(profile);
			}
		}
		if (StringUtils.isNotEmpty(timeFormat)) {
			Profile profile = profilePersistence.getProfileByColumnAndPbx("timeformat", pbxId);
			if (profile == null) {
				Profile p = new Profile(0, "timeformat", timeFormat, "timeFormat", 0, ProfileType.GENERAL, pbx);
				profilePersistence.save(p);
			} else {
				profile.setName(timeFormat);
			}
		}

		if (StringUtils.isNotEmpty(dateFormat)) {
			Profile profile = profilePersistence.getProfileByColumnAndPbx("dateformat", pbxId);
			if (profile == null) {
				Profile p = new Profile(0, "dateformat", dateFormat, "dateFormat", 0, ProfileType.GENERAL, pbx);
				profilePersistence.save(p);
			} else {
				profile.setName(dateFormat);
			}
		}

		if (StringUtils.isNotEmpty(durationFormat)) {
			Profile profile = profilePersistence.getProfileByColumnAndPbx("durationformat", pbxId);
			if (profile == null) {
				Profile p = new Profile(0, "durationformat", durationFormat, "durationFormat", 0, ProfileType.GENERAL,
						pbx);
				profilePersistence.save(p);
			} else {
				profile.setName(durationFormat);
			}
		}
		// delete
		for (Profile profile : profiles) {
			if (!remains.contains(profile) && !profile.getProfileType().equals(ProfileType.GENERAL)) {
				profilePersistence.delete(profile);
			}
		}

	}

	/**
	 * delete entity
	 * 
	 * @param profileId
	 */
	@Transactional(readOnly = false)
	public void deleteProfile(Long profileId) {
		profilePersistence.execute("delete from Profile p where p.id = ?1", profileId);
	}

	/**
	 * check name of PBX
	 * 
	 * @param name
	 * @return
	 */
	public boolean hasPBXName(String name) {
		PBX pbx = profilePersistence.findSingleObject(PBX.class, "name", name);
		return pbx != null ? true : false;
	}

	/**
	 * check name of Trunk
	 * 
	 * @param name
	 * @return
	 */
	public boolean hasTrunkName(String name) {
		Trunk trunk = profilePersistence.findSingleObject(Trunk.class, "name", name);
		return trunk != null ? true : false;
	}

	/**
	 * check name of user
	 * 
	 * @param name
	 * @return
	 */
	public boolean hasUserName(String name) {
		Contact user = profilePersistence.findSingleObject(Contact.class, "name", name);
		return user != null ? true : false;
	}
}
